#pragma once
#include "constant.h"
#include <memory>
#include <vector>
#include <string>
#include "card_generator.h"
#include "card_compartor.h"
namespace dymy
{

    namespace table
    {
        enum class Role : int8_t
        {
            ROLE_NONE = -1,
            ROLE_FARMER = 0,
            ROLE_LANDLORD = 1
        };

        class Person
        {
        public:
            ID_t user_id;                     //用户id
            std::string user_name;            //用户名
            Role role;                        //用户角色
            bool prepared;                    //用户是否已经准备
            int status;                       //用户当前状态
            std::vector<card_t> played_cards; //记录用户已经出过的牌

        public:
            multiple_card_t cards; //用户手上的牌
            void FillCards(multiple_card_t &&cards) noexcept;
            bool delete_in(const std::vector<card_t> &cards);
            Person(ID_t id, const std::string &user_name);
            Person();
            Person(const Person &) = default;
            Person(Person &&) = default;
            Person &operator=(const Person &) = default;
            Person &operator=(Person &&) = default;
            ~Person() = default;
        };

        template <card_size_t PN, card_size_t HN>
        class CardTable
        {
        public:
            typedef std::vector<card_t> HoleCards;
            typedef Person *PersonPtr;
            typedef std::unique_ptr<Person> PersonUPtr;
            typedef std::array<PersonUPtr, PN> Persons;

        public:
            const ID_t m_table_id;
            ssize_t m_current_table_landlord_index; //当前桌子哪个位置是地主
            ssize_t m_prev_play_max_card_index;     //上局出最大牌的用户
            //当局出最大牌
            std::unique_ptr<compartor::CardsClassify> m_current_play_max_cards;

            Persons m_persons;
            ssize_t m_step;

            HoleCards hole_cards_;

        public:
            explicit CardTable(ID_t table_id) : m_table_id(table_id), m_current_table_landlord_index(-1),
                                                m_prev_play_max_card_index(-1),
                                                m_current_play_max_cards(),
                                                m_persons(),
                                                m_step(STEP_WATING), hole_cards_()
            {
            }
            CardTable(const CardTable &) = delete;
            CardTable(CardTable &&) = default;
            CardTable &operator=(const CardTable &) = delete;
            CardTable &operator=(CardTable &&) = default;
            ~CardTable() = default;
            inline PersonUPtr &find_user(size_t index)
            {
                return m_persons[index];
            };

            inline ssize_t find_user_index_by_user_id(ID_t person_id) const
            {
                for (size_t i = 0; i < m_persons.size(); ++i)
                {
                    auto &p = m_persons[i];
                    if (p && p->user_id == person_id)
                    {
                        return i;
                    }
                }
                return -1;
            };

            inline ID_t get_table_id() const
            {
                return m_table_id;
            };

            inline ssize_t get_step()
            {
                return m_step & ~STEP_MASK;
            };

            inline ssize_t get_step_index()
            {
                return m_step & STEP_MASK;
            };

            inline ssize_t get_landlord_index()
            {
                if (get_step() == STEP_ALLOT)
                {
                    return get_step_index();
                }
                return -1;
            };

            inline ssize_t get_play_cards_index()
            {
                if (get_step() == STEP_PLAYING)
                {
                    return get_step_index();
                }
                return -1;
            };

            inline ssize_t get_winner_index()
            {
                if (get_step() == STEP_FINISHED)
                {
                    return get_step_index();
                }
                return -1;
            };

            inline const Persons &get_persons() const
            {
                return m_persons;
            };

            inline ssize_t get_prev_play_max_card_index() const
            {
                return m_prev_play_max_card_index;
            };

            inline ssize_t get_current_table_landlord_index() const
            {
                return m_current_table_landlord_index;
            };

            inline std::unique_ptr<compartor::CardsClassify> &get_current_play_max_cards()
            {
                return m_current_play_max_cards;
            };

            inline const HoleCards &get_cards3() const
            {
                return hole_cards_;
            };

            inline ssize_t find_free_position() const
            {
                for (size_t i = 0; i < m_persons.size(); ++i)
                {
                    auto &p = m_persons[i];
                    if (!p)
                    {
                        return i;
                    }
                }
                return -1;
            };

            inline bool has_person() const
            {
                for (size_t i = 0; i < m_persons.size(); ++i)
                {
                    auto &p = m_persons[i];
                    if (p)
                    {
                        return true;
                    }
                }
                return false;
            };
            inline PersonPtr find_user(size_t index, ID_t person_id) const
            {
                auto &p = m_persons[index];
                if (p && p->user_id == person_id)
                {
                    return p.get();
                }
                return nullptr;
            };

            inline void set_step(int step, int step_index = 0)
            {
                m_step = step | step_index;
            };
        };

        template <card_size_t AN, card_size_t PN, card_size_t EN, card_size_t HN, typename G = generator::CardGenerator<Person, AN, PN, EN, HN>>
        class TableController
        {
            typedef Person *PersonPtr;
            std::shared_ptr<G> generator_ptr_;

        public:
            typedef CardTable<PN, HN> CardTable_;
            typedef G CardGenerator_;

        public:
            TableController(const std::shared_ptr<G> &generator_ptr) : generator_ptr_(generator_ptr) {}

        public:
            //1添加用户成功
            //2该座位已经有人
            //0已经在这个房间
            //ERROR_PROCESS 流程错误，这个牌桌不处于等待、完成状态的时候
            int add_person(CardTable_ *ptr, size_t index, ID_t person_id, const std::string &user_name)
            {
                auto &p = ptr->find_user(index);
                if (!p)
                {
                    p.reset(new Person(person_id, user_name));
                    return 1;
                }
                else if (p->user_id != person_id)
                {
                    return 2;
                }
                else
                {
                    auto step = ptr->get_step();
                    if (step != STEP_WATING && step != STEP_FINISHED)
                    {
                        return ERROR_PROCESS;
                    }

                    return 0;
                }
            }

            //1添加退出成功
            //0该位置没有这个人
            int remove_person(CardTable_ *ptr, size_t index, ID_t person_id)
            {
                auto &p = ptr->find_user(index);
                if (p && p->user_id == person_id)
                {
                    p.reset(nullptr);
                    return 1;
                }
                return 0;
            }

            //-1：开始游戏失败,
            //-2人员不齐
            // 1:开始游戏成功,
            //开始游戏
            int start(CardTable_ *ptr)
            {
                auto step = ptr->get_step();
                if (step != STEP_WATING && step != STEP_FINISHED)
                {
                    return ERROR_PROCESS;
                }

                auto &pp = ptr->get_persons();
                for (size_t i = 0; i < pp.size(); ++i)
                {
                    auto &p = pp[i];
                    if (!p)
                    {
                        return ERROR_PLAYING_LACK_PERSON;
                    }

                    if (!p->prepared)
                    {
                        return ERROR_PLAYING_NOT_PREPARE;
                    }
                }

                //    printf("start gen cards\n");
                //    set_step(STEP_GENERAT_CARDS);
                generate_cards(ptr); //生成cards
                //    printf("end gen cards\n");

                if (ptr->m_current_table_landlord_index < 0)
                {
                    ptr->m_current_table_landlord_index = 0; //首次先分配第0个位置先抢地主
                }
                else
                {
                    ptr->m_current_table_landlord_index = (ptr->m_current_table_landlord_index + 1) % pp.size(); //之后的地主每次轮回
                }

                ptr->set_step(STEP_ALLOT, ptr->m_current_table_landlord_index);

                ptr->m_prev_play_max_card_index = -1; //不知道谁是地主，所以不知道谁出牌，记录为-1

                for (size_t i = 0; i < pp.size(); ++i)
                {
                    auto &p = pp[i];
                    if (p)
                    {
                        if (i == ptr->m_current_table_landlord_index)
                        {
                            p->status = PERSON_STEP_ALLOT_PROCESS;
                        }
                        else
                        {
                            p->status = PERSON_STEP_ALLOT_WAITING;
                        }
                    }
                }

                return 1;
            }

            //1:准备成功
            //0:取消准备成功
            //2:传参与该用户参数相同
            //准备游戏
            int prepared(CardTable_ *ptr, size_t index, ID_t person_id, bool prepared)
            {
                auto p = ptr->find_user(index, person_id);
                if (!p)
                {
                    return ERROR_EMPTY_PERSON;
                }
                auto stp = ptr->get_step();

                if (stp != STEP_WATING && stp != STEP_FINISHED)
                {
                    return ERROR_PROCESS;
                }

                if (p->prepared != prepared)
                {
                    p->prepared = prepared;
                    p->role = Role::ROLE_FARMER;
                    p->cards.clear();
                    if (prepared)
                    {
                        return 1;
                    }
                    else
                    {
                        return 0;
                    }
                }
                return 2;
            }

            // 0:不抢，1:抢地主成功 ,2:都不抢地主
            //用户开始抢地主
            int rob_landlord(CardTable_ *ptr, size_t index, ID_t person_id, bool rob)
            {
                auto p = ptr->find_user(index, person_id);
                if (!p)
                {
                    return ERROR_EMPTY_PERSON;
                }

                if (ptr->get_step() != STEP_ALLOT)
                {
                    return ERROR_PROCESS;
                }

                ssize_t curr_landlord_index = ptr->get_step_index();
                if (curr_landlord_index != index)
                {
                    return ERROR_NOT_SELF;
                }

                if (rob)
                {
                    p->role = Role::ROLE_LANDLORD;
                    for (auto begin = ptr->hole_cards_.cbegin(); begin != ptr->hole_cards_.cend(); ++begin)
                    {
                        p->cards.insert(*begin);
                    }

                    ptr->set_step(STEP_PLAYING, index);
                    ptr->m_prev_play_max_card_index = -1; //首次出牌，所以记录为-1

                    for (size_t i = 0; i < ptr->get_persons().size(); ++i)
                    {
                        auto &p = ptr->find_user(i);
                        if (p)
                        {
                            if (i == curr_landlord_index)
                            {
                                p->status = PERSON_STEP_PLAING;
                            }
                            else
                            {
                                p->status = PERSON_STEP_PLAING_WAITING;
                            }
                        }
                    }

                    return 1;
                    //        (*(pp+index))->cards.role = 1;
                }
                else
                {
                    //让下一个人开始抢地主
                    ssize_t next = (curr_landlord_index + 1) % ptr->get_persons().size();
                    if (next != ptr->m_current_table_landlord_index)
                    {
                        //如果不抢地主，那么返回0，让下一个人抢
                        ptr->set_step(STEP_ALLOT, next);
                        auto &current_p = ptr->get_persons()[curr_landlord_index];
                        if (current_p)
                        {
                            current_p->status = PERSON_STEP_ALLOT_REJECT;
                        }
                        auto &next_p = ptr->get_persons()[next];
                        if (next_p)
                        {
                            next_p->status = PERSON_STEP_ALLOT_PROCESS;
                        }
                        return 0;
                    }
                    else
                    {
                        //如果三个人都不抢地主,那么重新洗牌
                        generate_cards(ptr);                                                                                         //生成cards
                        ptr->m_current_table_landlord_index = (ptr->m_current_table_landlord_index + 1) % ptr->get_persons().size(); //地主变为下一个人

                        ptr->set_step(STEP_ALLOT, ptr->m_current_table_landlord_index);
                        ptr->m_prev_play_max_card_index = -1; //不知道谁是地主，所以不知道谁出牌，记录为-1

                        for (size_t i = 0; i < ptr->get_persons().size(); ++i)
                        {
                            auto &p = ptr->get_persons()[i];
                            if (p)
                            {
                                if (i == ptr->m_current_table_landlord_index)
                                {
                                    p->status = PERSON_STEP_ALLOT_PROCESS;
                                }
                                else
                                {
                                    p->status = PERSON_STEP_ALLOT_WAITING;
                                }
                            }
                        }

                        return 2;
                    }
                }
            }

            //0:要不起
            //1:出牌成功
            //2:游戏结束
            int play_cards(CardTable_ *ptr, size_t index, ID_t person_id, const std::vector<uint8_t> &cards)
            {
                auto p = ptr->find_user(index, person_id);

                if (!p)
                {
                    return ERROR_EMPTY_PERSON;
                }

                if (ptr->get_step() != STEP_PLAYING)
                {
                    return ERROR_PROCESS;
                }

                ssize_t curr_play_index = ptr->get_step_index();

                if (index != curr_play_index)
                {
                    //如果没轮到该人出牌
                    return ERROR_NOT_SELF;
                }

                if (ptr->m_prev_play_max_card_index < 0 || curr_play_index == ptr->m_prev_play_max_card_index)
                {
                    /*如果首次地主出牌时出了空牌，那么不允许
             * 如果另外两个人都要不起，轮到这个人出牌时，也不允许出空牌
             * */

                    if (cards.size() == 0)
                    {
                        //地主首次不能出空牌
                        return ERROR_CARDS;
                    }
                    else
                    {
                        return play_cards_internal(ptr, index, p, cards);
                    }
                }
                else
                {
                    if (cards.size() == 0)
                    {
                        ssize_t next = (curr_play_index + 1) % ptr->get_persons().size();
                        ptr->set_step(STEP_PLAYING, next);
                        if (next == ptr->m_prev_play_max_card_index)
                        {
                            //如果这两个人要不起那个人的牌，清除那个人出的牌，并且重新让那个人出牌，
                            ptr->m_current_play_max_cards.reset(nullptr);

                            //如果这两个人要不起那个人的牌，清除所有人记录的牌
                            for (size_t i = 0; i < ptr->get_persons().size(); ++i)
                            {
                                auto &ip = ptr->find_user(i);
                                if (ip)
                                {
                                    ip->played_cards.clear();
                                }
                            }
                        }

                        auto &current_p = ptr->get_persons()[curr_play_index];
                        if (current_p)
                        {
                            current_p->status = PERSON_STEP_PLAING_NOT_AFFORD;
                        }
                        auto &next_p = ptr->get_persons()[next];
                        if (next_p)
                        {
                            next_p->status = PERSON_STEP_PLAING;
                            next_p->played_cards.clear();
                        }

                        //如果该人要不起上个人的牌
                        return 0;
                    }
                    else
                    {
                        return play_cards_internal(ptr, index, p, cards);
                        //如果是首次地主出牌
                    }
                }
            }

            void stop(CardTable_ *ptr)
            {
                release(ptr, true);
                ptr->set_step(STEP_WATING);
            };

            ssize_t stop_table_if_user_quit(CardTable_ *ptr, ID_t person_id)
            {
                ssize_t index = ptr->find_user_index_by_user_id(person_id);
                if (index >= 0)
                {
                    stop(ptr);
                    return index;
                }
                return -1;
            }

            void generate_cards(CardTable_ *ptr)
            {
                ptr->hole_cards_.clear();
                generator_ptr_->MakeCards(ptr->m_persons, ptr->hole_cards_);
            };

        private:
            int play_cards_internal(CardTable_ *ptr, size_t index, PersonPtr p, const std::vector<card_t> &cards)
            {
                compartor::CardsClassify cards_classify;
                cards_classify.compute_cards(cards);
                if (cards_classify.is_invalid())
                {
                    //如果这个人出的牌有问题
                    return ERROR_CARDS;
                }
                else if (ptr->m_current_play_max_cards && cards_classify <= (*(ptr->m_current_play_max_cards)))
                {
                    //如果用户出的牌比上个人出的牌小
                    return ERROR_CARDS;
                }
                else if (!p->delete_in(cards))
                {
                    //如果用户出的牌不存在
                    return ERROR_CARDS;
                }
                else
                {
                    if (p->cards.size() == 0)
                    {
                        ptr->set_step(STEP_FINISHED, index);

                        for (size_t i = 0; i < ptr->get_persons().size(); ++i)
                        {
                            auto &ip = ptr->get_persons()[i];
                            if (ip)
                            {
                                //相同的角色胜利
                                if (ip->role == p->role)
                                {
                                    ip->status = PERSON_STEP_FINISHED_SUCCESS;
                                }
                                else
                                {
                                    ip->status = PERSON_STEP_FINISHED_FAILED;
                                }
                                ip->played_cards.clear();
                            }
                        }
                        //释放，主要是为了让用户重新准备，才能重新开始游戏
                        release(ptr);

                        return 2;
                    }
                    else
                    {
                        ptr->m_current_play_max_cards.reset(new compartor::CardsClassify(std::move(cards_classify)));

                        ptr->m_prev_play_max_card_index = index;

                        ssize_t next = (ptr->m_prev_play_max_card_index + 1) % ptr->get_persons().size();
                        ptr->set_step(STEP_PLAYING, next);

                        auto &current_p = ptr->get_persons()[index];
                        if (current_p)
                        {
                            current_p->status = PERSON_STEP_PLAING_YET;
                            current_p->played_cards = cards;
                        }
                        auto &next_p = ptr->get_persons()[next];
                        if (next_p)
                        {
                            next_p->status = PERSON_STEP_PLAING;
                            next_p->played_cards.clear();
                        }

                        return 1;
                    }
                }
            };

            void release(CardTable_ *ptr, bool clear_cards = false)
            {
                ptr->m_prev_play_max_card_index = -1;
                ptr->m_current_play_max_cards.reset(nullptr);

                for (size_t i = 0; i < ptr->get_persons().size(); ++i)
                {
                    auto &p = ptr->find_user(i);
                    if (p)
                    {
                        p->prepared = false;
                        if (clear_cards)
                        {
                            p->cards.clear();
                            p->status = PERSON_STEP_WAITING;
                            p->played_cards.clear(); //清除已经打出的牌
                        }
                    }
                }
            }
        };

    }
}
